<template>
  <div class="RP11">
    <el-scrollbar class="main" :scroll-y="true">
      <div class="imgs">
        <div
          v-for="(item, index) in fileList"
          :key="item.name"
          :title="exportExcelData.length ? exportExcelData[index][1] : ''"
        >
          <el-image
            class="img"
            :class="[
              item.name ? 'img_' + index : '',
              active === index ? 'active' : '',
            ]"
            :src="item.url"
            :preview-src-list="preList"
            :initial-index="index"
            @load="item.load = true"
          >
          </el-image>

          <!-- <img
            class="img"
            :class="[item.name ? 'img_' + index : '']"
            :src="item.url"
            :key="item.name"
            alt=""
          /> -->
          <p>{{ item.name }}</p>
        </div>
      </div>
      <!-- <canvas id="canvas"></canvas> -->
      <!-- <div class="templates"></div> -->
      <!-- <div class="templates">
        <div class="item" :key="item" v-for="item in templatesList">
          {{ item }}
        </div>
      </div> -->
    </el-scrollbar>

    <!-- <div>处理结果: 发现{{ result.length }}个亮点，分别为
        <p v-for="item in result" :key="item.value">{{ item }}</p>
      </div> -->

    <div class="panel">
      <!-- <el-button
        class="btn"
        style="width: 120px;"
        type="primary"
        size="small"
        @click="dialogShow"
        >设置阳性判断值</el-button
      > -->
      <div class="btns">
        <!-- <div class="btn">
          <el-upload
            class="upload-demo"
            action="#"
            multiple
            :file-list="fileList"
            :show-file-list="false"
            :on-change="onchange"
            :auto-upload="false"
          >
            <el-button
              class="btn"
              slot="trigger"
              size="mini"
              plain
              type="primary"
              >选择图片</el-button
            >
          </el-upload>
        </div> -->
        <el-button
          class="btn"
          type="primary"
          size="small"
          @click="selectPath('multiSelections')"
          >选择图片</el-button
        >
        <el-button
          class="btn"
          type="primary"
          size="small"
          @click="selectPath('openDirectory')"
          >选择路径</el-button
        >
        <el-button class="btn" type="default" size="small" @click="clear"
          >清空图片</el-button
        >
        <!-- <el-button
          class="btn"
          size="mini"
          type="default"
          @click="exportDialog = !exportDialog"
          >导出设置</el-button
        > -->
      </div>
      <el-divider></el-divider>
      <div class="row">
        {{ isCropping ? "开启" : "关闭" }}裁剪
        <el-switch style="margin-left: 10px;" v-model="isCropping"> </el-switch>
      </div>
      <el-divider></el-divider>
      <div class="block">
        <div class="row">
          选择对照
        </div>
        <div class="row">
          <el-select
            value-key="name"
            size="small"
            v-model="compareIndex"
            placeholder="请选择"
          >
            <el-option
              v-for="(item, index) in fileList"
              :key="item.name"
              :label="item.name"
              :value="index"
            >
            </el-option>
          </el-select>
        </div>
        <div class="row">
          <el-button class="btn" type="default" size="small" @click="handler"
            >处理图片</el-button
          >
          <el-button
            class="btn"
            type="default"
            size="small"
            @click="exportShow"
            >导出结果</el-button
          >
        </div>
      </div>
      <fragment v-if="version === 'tester'">
        <el-divider></el-divider>
        <div class="block">
          <div class="row">
            结论在第几行?
            <el-select
              class="input"
              size="mini"
              v-model="resultIndex"
              placeholder="请选择"
            >
              <el-option
                v-for="item in 9"
                :key="item + 1"
                :label="item + 1"
                :value="item + 1"
              >
              </el-option>
            </el-select>
          </div>
          <div class="row">
            <el-button
              class="btn"
              type="primary"
              size="mini"
              plain
              @click="selectResult"
              >导入结论</el-button
            >
          </div>

          <div class="row">
            选择结论组名
            <el-select
              class="input"
              size="mini"
              v-model="resultKey"
              placeholder="请选择"
            >
              <el-option
                v-for="(value, key) of resultObj"
                :key="key"
                :label="key"
                :value="key"
              >
              </el-option>
            </el-select>
          </div>
          <div class="row">
            <el-button
              class="btn"
              type="primary"
              size="mini"
              plain
              @click="resultContrast"
              >结果对比</el-button
            >
          </div>
        </div>
      </fragment>
      <!-- <fragment>
        <el-divider></el-divider>
        <el-button
          class="btn"
          type="primary"
          size="mini"
          plain
          @click="exportConfig"
          >导出模板</el-button
        >
        <div class="block">
          <div class="row">
            <el-tag size="small">普通点</el-tag>
          </div>
          <div class="row">
            动态筛选亮点比例：
          </div>
          <div class="row">
            最小面积：
            <el-input
              class="input"
              size="mini"
              v-model="normal.trendsCount.minContourArea"
            ></el-input>
          </div>
          <div class="row">
            大于：
            <el-input
              class="input"
              size="mini"
              v-model="normal.trendsCount.min"
            ></el-input>
            小于：
            <el-input
              class="input"
              size="mini"
              v-model="normal.trendsCount.max"
            ></el-input>
          </div>
          <div class="row">
            颗粒度：
            <el-input
              class="input"
              size="mini"
              v-model="normal.trendsCount.particle"
            ></el-input>
          </div>

          <div v-for="(item, index) in normal.trendsCount.rules" :key="index">
            <div class="row">
              圆形度大于
              <el-input
                class="input"
                size="mini"
                v-model="item.circularity"
              ></el-input>
            </div>
            <div class="row">
              圆心偏移 x:
              <el-input
                class="input"
                size="mini"
                v-model="item.ri.x"
              ></el-input>
              y:
              <el-input
                class="input"
                size="mini"
                v-model="item.ri.y"
              ></el-input>
            </div>
          </div>
        </div>
      </fragment> -->
      <el-divider></el-divider>
      <el-scrollbar class="List">
        <div class="Table">
          <div class="t-row t-head">
            <div class="t-column-1">项目</div>
            <div class="t-column-2">结论</div>
          </div>
          <div
            class="t-row"
            v-for="(item, index) in exportExcelData"
            :key="index"
            @click="activeChange(index)"
          >
            <div class="t-column-1" :title="item[0]">{{ item[0] }}</div>
            <div class="t-column-2" :title="item[1]">{{ item[1] }}</div>
          </div>
        </div>
      </el-scrollbar>
    </div>
    <el-dialog
      title="设置"
      :visible.sync="exportDialog"
      :before-close="beforeClose"
    >
      <el-form
        class="form"
        ref="ruleForm"
        label-position="right"
        label-width="100px"
        :model="form"
      >
        <el-form-item
          label="文件夹名称"
          prop="mkdir"
          :rules="[
            {
              max: 20,
              message: '文件名称超过20字符，请重新输入',
              trigger: 'blur',
            },
          ]"
        >
          <div class="item">
            <el-input v-model="form.mkdir"></el-input>
          </div>
        </el-form-item>
        <el-form-item label="输出目录">
          <div class="item">
            <el-input
              v-model="form.path"
              :title="form.path"
              disabled
            ></el-input>
            <el-button class="btn" type="default" @click="selectExportPath"
              >浏览</el-button
            >
          </div>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button @click="beforeClose(() => (exportDialog = false))"
          >取 消</el-button
        >
        <el-button
          type="primary"
          @click="saveExport(() => (exportDialog = false))"
          >导 出</el-button
        >
      </div>
    </el-dialog>
    <el-dialog
      title="设置阳性判断值"
      :visible.sync="Dialog"
      :before-close="dialogCancel"
      align="center"
    >
      <div class="Dialog-box">
        <div class="box" v-for="(item, index) in determine_RP11" :key="index">
          <fragment v-for="(value, key) in item" :key="key">
            <p>{{ key }}</p>
            <el-input
              class="input"
              :value="item[key]"
              @input="onInput($event, item)"
            ></el-input>
          </fragment>
        </div>
      </div>
      <div slot="footer" class="dialog-footer">
        <el-button @click="dialogCancel">取 消</el-button>
        <el-button type="primary" @click="dialogSave">保 存</el-button>
      </div>
    </el-dialog>
  </div>
</template>

<script>
// import { np } from numpy;
// import { cv } from cv2;
import XLSX from "xlsx";
import { subInvoke } from "../../utils/subprocess";
import { parseTime, mathCount } from "../../utils/index";
import { mapState } from "vuex";
import { AI } from "../../api/app";

export default {
  name: "RP11",
  data() {
    return {
      group: "1-1",
      templatesList: [
        "SA",
        "BM",
        "TL",
        "EC",
        "LG",
        "SMY",
        "FL",
        "HN",
        "FK",
        "YG",
        "MC",
        "IC",
      ],
      isCropping: false,
      fileList: [],
      compareIndex: 0,
      active: "",
      preList: [],
      exportDialog: false,
      Dialog: false,
      gate: 0,
      height: 0,
      width: 0,
      templates: [],
      compare: [],
      result: [],
      ratio: 0.23,
      ratios: [],
      resultIndex: 3,
      resultObj: null,
      resultKey: "",
      resultKeyReserve: "",
      normal: {
        trendsCount: {
          minContourArea: 168,
          max: 0.33,
          min: 0.15,
          particle: 0.01,
          rules: [
            { circularity: 0.72, ri: { x: 3.9, y: 3.9 } },
            { circularity: 0.85, ri: { x: 10, y: 10 } },
          ],
        },
      },
      exportExcelData: [],
      resultContrastData: [],
      compareIndex: "",
      form: {
        mkdir: "",
        path: "",
      },
      oldForm: {
        mkdir: "",
        path: "",
      },
      determine_RP11: [],
      fullscreenLoading: null,
    };
  },
  watch: {
    fileList: {
      handler(n, o) {
        if (n.length) {
          const p = n.every((v) => v.load);
          console.log(p);
          if (p) {
            if (this.fullscreenLoading) {
              this.fullscreenLoading.close();
              this.fullscreenLoading = null;
            }
          }
        } else {
          if (this.fullscreenLoading) {
            this.fullscreenLoading.close();
            this.fullscreenLoading = null;
          }
        }
      },
      deep: true,
    },
  },
  computed: {
    version() {
      return this.$store.state.app.version;
    },
  },
  mounted() {
    console.log(this.$store.state.app.AI);
    console.log("RP11");
    // const fs = require("fs");
    // const base = this.$store.state.app.static;
    // const path = require("path");
    // const filepath = path.join(base, "determine_RP11.json");
    // const jsonData = fs.readFileSync(filepath, "utf-8");
    // this.determine_RP11 = JSON.parse(jsonData);

    // const t = this.findTemplate();
    // console.log(t);

    let mkdirName = localStorage.getItem("mkdir-RP11") || "RP11分析结果";
    let savePath = localStorage.getItem("savePath-RP11");

    if (!savePath) {
      const path = require("path");

      const desktopPath = path.join(require("os").homedir(), "Desktop");

      savePath = desktopPath;
    }

    this.form = {
      mkdir: mkdirName,
      path: savePath,
    };
    this.oldForm = {
      mkdir: mkdirName,
      path: savePath,
    };
  },
  methods: {
    // onchange(file, fileList) {
    //   console.log(file);
    //   if (fileList.length > 1) {
    //     const i = fileList.findIndex((v) => {
    //       return v.name === file.name;
    //     });
    //     if (i !== fileList.length - 1) {
    //       fileList.pop();
    //       this.fileList = fileList;
    //       return;
    //     }
    //   }
    //   this.fileList = fileList.map((v) => {
    //     if (!v.url) {
    //       v.url = URL.createObjectURL(v.raw);
    //     }
    //     return v;
    //   });
    //   this.compareIndex = this.fileList.length - 1;
    // },
    dialogShow() {
      this.Dialog = true;
    },
    onInput(e, item) {
      item[Object.keys(item)[0]] = e.replace(/[^0-9]/g, "");
    },
    dialogCancel() {
      const fs = require("fs");
      const base = this.$store.state.app.static;
      const path = require("path");
      const filepath = path.join(base, "determine_RP11.json");
      const jsonData = fs.readFileSync(filepath, "utf-8");
      this.determine_RP11 = JSON.parse(jsonData);
      this.Dialog = false;
    },
    dialogSave() {
      this.determine_RP11.find((v) => {
        const key = Object.keys(v)[0];
        if (!v[key]) {
          v[key] = 0;
        }
      });

      const base = this.$store.state.app.static;
      const path = require("path");
      const filepath = path.join(base, "determine_RP11.json");

      subInvoke("saveJson", {
        filepath: filepath,
        data: JSON.stringify(this.determine_RP11),
      });
      this.Dialog = false;
    },
    activeChange(index) {
      this.active = index;

      const dom = document.querySelector(`.RP11 .img_${index}`).parentNode;
      const context = document.querySelector(".RP11 .main .el-scrollbar__wrap");

      const height = context.scrollHeight;
      if (dom.offsetTop - 16 > height) {
        context.scrollTop = height;
      } else {
        context.scrollTop = dom.offsetTop - 16;
      }
    },
    selectExportPath() {
      this.openFile({
        mothod: "openDirectory",
      }).then((path) => {
        console.log(path);
        if (path) {
          this.form.path = path;
        }
      });
    },
    beforeClose(next) {
      const { mkdir, path } = this.oldForm;
      this.form = {
        mkdir,
        path,
      };
      next();
    },
    exportShow() {
      if (!this.exportExcelData.length) {
        this.$alert("请先处理图片", "提醒", {
          confirmButtonText: "确定",
          callback: (action) => {},
        });
        return;
      }
      this.exportDialog = true
    },
    saveExport(next) {
      this.$refs["ruleForm"].validate((valid) => {
        if (valid) {
          const { mkdir, path } = this.form;

          this.oldForm = {
            mkdir,
            path,
          };
          localStorage.setItem("mkdir-RP11", mkdir);
          localStorage.setItem("savePath-RP11", path);

          this.exportExcel(this.exportExcelData, path, mkdir, true);

          next();
        }
      });
    },
    selectPath(type) {
      const fs = require("fs");

      this.openFile({
        type: "img",
        mothod: type,
      }).then((res) => {
        if (res && res.length) {
          this.fileList = [];
        }
        this.fullscreenLoading = this.$loading({
          fullscreen: true,
          lock: true,
          text: "图片正在加载中...",
          spinner: "el-icon-loading",
          background: "rgba(0, 0, 0, 0.7)",
        });

        setTimeout(() => {
          if (res && res.length) {
            let preList = [];
            const p = res.some((v) => {
              const data = fs.readFileSync(v.path);
              if (data.length > 2 * 1024 * 1024) {
                return true;
              }

              const names = v.name.split(".");
              const type = names[names.length];

              // const imageBlob = new Blob([data], { type: "image/jpg" });
              // const imageUrl = URL.createObjectURL(imageBlob);

              const imageUrl = Buffer.from(data).toString("base64");

              v.url = "data: image/" + type + ";base64," + imageUrl;
              v.base64 = imageUrl;
              v.load = false;
              // preList.push(imageUrl);
              // return v;
            });
            if (!p) {
              this.fileList = res.sort((f1, f2) => {
                if (f1.name.includes("阴性对照")) {
                  return true;
                } else if (
                  f1.name.includes("阳性对照") &&
                  f2.name.includes("阴性对照")
                ) {
                  return true;
                } else if (f1.name.includes("阳性对照")) {
                  return false;
                }
                const reg = /(\d+)/;
                const aIndex = f1.name.match(reg)[1];
                const bIndex = f2.name.match(reg)[1];
                return aIndex - bIndex;
              });
              this.fileList.map((v) => {
                preList.push(v.url);
              });
              this.preList = preList;

              this.exportExcelData = [];
              this.active = "";
            } else {
              this.$message.error("图片大小超过2MB，请确认后再尝试上传");
            }
          } else {
            this.fullscreenLoading.close();
            this.fullscreenLoading = null;
            return;
            // this.fileList = [];
            // this.preList = [];
          }
          if (this.fileList.length) {
            this.compareIndex = this.fileList.length - 1;

            const path = this.fileList[0].path;
            const names = path.split("\\");
            const groupName = names[names.length - 2];
            if (
              this.resultObj &&
              Object.keys(this.resultObj).includes(groupName)
            ) {
              this.resultKey = groupName;
            } else {
              this.resultKeyReserve = groupName;
            }
          } else {
            this.compareIndex = "";
          }
        }, 50);
      });
    },
    selectResult() {
      this.openFile({
        mothod: "openFile",
      }).then((res) => {
        console.log(res);

        const filePath = res; // 指定 Excel 文件路径
        const workbook = XLSX.readFile(filePath);
        const sheetName = workbook.SheetNames[0]; // 假设只有一个工作表
        const worksheet = workbook.Sheets[sheetName];
        const jsonData = XLSX.utils.sheet_to_json(worksheet, { header: 1 });
        console.log("Excel 数据:", jsonData);

        const map = new Map();
        for (let i = 1; i < jsonData.length; i++) {
          const item = jsonData[i];
          const group = item[0];
          const name = item[1];
          const result = item[this.resultIndex - 1] + "";
          const sortNumber = [...this.templatesList];
          const sort = result.split("、").sort((f1, f2) => {
            return sortNumber.indexOf(f1) - sortNumber.indexOf(f2);
          });
          const str = sort.join("、");

          if (map.get(group)) {
            const arr = map.get(group).concat([[name, str]]);
            map.set(group, arr);
          } else {
            const arr = [[name, str]];
            map.set(group, arr);
          }
        }
        const json = {};
        for (let [key, value] of map) {
          json[key] = value;
        }

        this.resultObj = json;
        if (
          this.resultKeyReserve &&
          Object.keys(json).includes(this.resultKeyReserve)
        ) {
          this.resultKey = this.resultKeyReserve;
          this.resultKeyReserve = "";
        } else {
          this.resultKey = Object.keys(json)[0];
        }
        console.log(JSON.stringify(json));

        this.$message({
          message: "导入成功",
          type: "success",
        });
      });
    },
    clear() {
      if (!this.fileList.length) {
        this.$message.error("当前无图片，无需清空");
        return;
      }
      this.$confirm("确定要清空图片吗?", "提示", {
        confirmButtonText: "确定",
        cancelButtonText: "取消",
        type: "warning",
      })
        .then(() => {
          this.fileList = [];
          this.compareIndex = "";
          this.$message({
            type: "success",
            message: "图片清空成功!",
          });
        })
        .catch(() => {});
    },
    handleCompare(mat) {
      const cv = global.cv;
      return new Promise((resolve) => {
        // const imgDom = document.querySelector(`.RP11 .${img} img`);
        // const mat = cv.imread(imgDom);

        this.segment(mat).then((imgs) => {
          const datas = imgs.map((v) => {
            let gray = new cv.Mat();

            cv.cvtColor(v.img, gray, cv.COLOR_RGBA2GRAY);

            let arr = [];
            for (let y = 0; y < gray.rows; y++) {
              for (let x = 0; x < gray.cols; x++) {
                const pixelValue = gray.ucharAt(y, x);
                // if (pixelValue >= 25.5) {
                arr.push(pixelValue);
                // }
              }
            }
            arr.sort((f1, f2) => {
              return f1 - f2;
            });

            // const average = mathCount(arr, "average");
            // const averageDeviation = mathCount(arr, "averageDeviation");
            // const sd = mathCount(arr, "sd");

            // const peaks = this.findPeaks2(arr);

            // gray.delete();
            // v.img.delete();

            return {
              arr: arr,
              gray: gray,
              img: v.img,
              // average: average,
              // averageDeviation: averageDeviation,
              // sd: sd,
              rules: v.rules,
              value: v.value,
            };
          });
          resolve(datas);
        });
      });
    },
    findRatio(arr, ratio) {
      return arr[Math.floor(arr.length * (1 - ratio))];
    },
    _trendsCount(item, rule, ai) {
      const ratios = this.getRatios(rule.min, rule.max, rule.particle);

      const results = [];
      const poinsArr = [];
      const ratiosArr = [];
      for (let ra = 0; ra < ratios.length; ra++) {
        const ratio = this.findRatio(item.arr, ratios[ra]);

        ratiosArr.push(ratio);

        const { circularitys, points } = this.findPoint(item, ratio, rule);

        results.push(circularitys);
        poinsArr.push(points);
      }
      console.log(results);
      const { value, index } = this.findTrendsMax(results);

      const f = ratiosArr[index[0]]
        ? this.findPoint(item, ratiosArr[index[0]], rule, true)
        : false;

      // console.log(value);

      // const rules = [
      //   { circularity: 0.65, ri: { x: 6.5, y: 6.5 } },
      //   { circularity: 0.82, ri: { x: 12, y: 12 } },
      // ];

      if (ai) {
        return f;
      }

      const rules = rule.rules;

      if (
        f &&
        ((value > 0.92 && f.light - f.dark > 10) ||
          (f.light - f.dark > 50 && value > 0.72))
      ) {
        return f;
      } else if (index[0] !== -1 && index[1] !== -1 && f) {
        let flag = false;
        const { x, y } = poinsArr[index[0]][index[1]];
        rules.map((v) => {
          if (
            value > v.circularity &&
            y < item.img.rows / 2 + v.ri.y &&
            y > item.img.rows / 2 - v.ri.y &&
            x < item.img.cols / 2 + v.ri.x &&
            x > item.img.cols / 2 - v.ri.x
          ) {
            flag = true;
          }
        });
        if (flag) {
          console.log({ x, y });
          return f;
          // return {
          //   value: value,
          //   ratio: ratiosArr[index[0]],
          //   point: poinsArr[index[0]][index[1]],
          // };
        }
      }
    },
    findTrendsMax(arr) {
      let max = 0;
      let index = -1;
      let num = -1;
      arr.map((v, i) => {
        if (v && v.length > 0) {
          v.map((u, j) => {
            if (u > max) {
              max = u;
              index = i;
              num = j;
            }
          });
        }
      });
      return {
        value: max,
        index: [index, num],
      };
    },
    async AIhandle() {
      const data = this.fileList.map((v) => {
        return {
          [v.name]: v.base64,
        };
      });

      const respones = await this.chunkApi(data);

      const templates = this.findTemplate();
      this.templates = templates.RP11;
      const result = this.AIresult(respones, this.templates);

      return result;
    },
    async AITransfer(result) {
      const obj = {};
      result.map((v) => {
        for (let key in v) {
          obj[key] = v[key];
        }
      });

      const cv = global.cv;

      let map = [];

      for (let i = 0; i < this.fileList.length; i++) {
        let imgDom = document.querySelector(".RP11 .img_" + i + " img");
        const rect = cv.imread(imgDom);
        // const rect = this.isCropping ? this.cropping(mat, i) : mat;
        imgDom = null;
        if (rect) {
          const arr = await this.handleCompare(rect);
          console.log(arr);
          rect.delete();
          let points = [];
          try {
            arr.map((v, index) => {
              const { rules, value } = v;

              if (obj[this.fileList[i].name].includes(index)) {
                const r = this._trendsCount(v, rules[0], true);
                points.push({
                  value: value,
                  number: Math.round(r.light - r.dark),
                });

                v.gray.delete();
                v.img.delete();
                v.gray = null;
                v.img = null;
              }
            });
            map.push([this.fileList[i].name, points]);
          } catch (err) {
            map.push([this.fileList[i].name, []]);
          }
        } else {
          map.push([this.fileList[i].name, []]);
        }
      }
      return map;
    },
    AIresult(respones, templates) {
      const t = templates.data;

      const result = respones.map((v) => {
        for (let key in v) {
          v[key] = v[key]
            .map((u) => {
              const point = {
                x: (u[0] + u[1]) / 2,
                y: (u[2] + u[3]) / 2,
              };
              const index = t.findIndex((w) => {
                return (
                  point.x >= w.left &&
                  point.y >= w.top &&
                  point.x < w.left + w.width &&
                  point.y < w.top + w.height
                );
              });
              return index;
            })
            .sort((f1, f2) => f1 - f2);
        }
        return v;
      });
      return result;
    },
    async chunkApi(data) {
      const chunkSize = 10;

      let respones = [];

      for (let i = 0; i < Math.ceil(data.length / chunkSize); i++) {
        let chunk = data.slice(i * chunkSize, (i + 1) * chunkSize);
        const res = await AI(chunk);
        respones = respones.concat(res);
      }

      return respones;
    },
    quantify(map) {
      let result = [];
      if (
        this.templates.compare &&
        (this.compareIndex === 0 || this.compareIndex)
      ) {
        const i = map[this.compareIndex][1].findIndex((v) => {
          return v.value === "IC";
        });
        if (i !== -1) {
          const baseMumber = map[this.compareIndex][1][i].number;

          result = map.map((v) => {
            const arr = [];
            v[1] = v[1].map((u) => {
              // const item = this.determine_RP11.find((v) => {
              //   return Object.keys(v)[0] == u.value;
              // });
              // if (
              //   !item ||
              //   Math.round((u.number / baseMumber) * 100) >=
              //     Object.values(item)[0]
              // ) {
              arr.push(
                u.value + ":" + Math.round((u.number / baseMumber) * 100)
              );
              // }
            });
            return [v[0], arr.join("、")];
          });
          this.exportExcelData = result;
        } else {
          result = map.map((v) => {
            v[1] = v[1].map((u) => {
              return u.value;
            });
            return [v[0], v[1].join("、")];
          });
          this.exportExcelData = result;
        }
      } else {
        result = map.map((v) => {
          v[1] = v[1].map((u) => {
            return u.value;
          });
          return [v[0], v[1].join("、")];
        });
        this.exportExcelData = result;
      }

      console.log(result);
      this.$message({
        message: "图片处理完成！",
        type: "success",
      });

      return result;
    },
    async handler() {
      let Loading;
      try {
        if (!this.fileList.length) {
          this.$alert("请先选择图片", "提醒", {
            confirmButtonText: "确定",
            callback: (action) => {},
          });
          return Promise.reject();
        }

        Loading = this.$loading({
          fullscreen: true,
          lock: true,
          text: "Loading",
          spinner: "el-icon-loading",
          background: "rgba(0, 0, 0, 0.7)",
        });

        if (this.$store.state.app.AI) {
          const res = await this.AIhandle();
          const map = await this.AITransfer(res);
          const reslut = await this.quantify(map);
          Loading.close();
        } else {
          setTimeout(() => {
            this.handle()
              .then(() => {
                Loading.close();
                return;
              })
              .finally((err) => {
                Loading.close();
              });
          }, 100);
        }
      } catch (e) {
        this.$alert("程序处理异常，请重启软件后再试", "提醒", {
          confirmButtonText: "确定",
          callback: (action) => {},
        });
        Loading && Loading.close();
        console.log(e);
      }
    },
    resultContrast() {
      if (!this.exportExcelData.length) {
        this.$alert("请先处理图片", "提醒", {
          confirmButtonText: "确定",
          callback: (action) => {},
        });
        return;
      }
      if (!this.resultObj) {
        this.$alert("请先导入结论", "提醒", {
          confirmButtonText: "确定",
          callback: (action) => {},
        });
        return;
      }
      if (!this.resultKey) {
        this.$alert("请先选择结论组名", "提醒", {
          confirmButtonText: "确定",
          callback: (action) => {},
        });
        return;
      }
      const map = this.exportExcelData;
      // const result = require("./result.json");
      // const result2 = result["2-2"];
      const result = this.resultObj;
      const result2 = result[this.resultKey];

      console.log(result2);

      let count = 0;
      let count2 = 0;
      let err = [];
      let err2 = [];
      let newMap = [];
      for (let i = 0; i < map.length; i++) {
        const item = map[i];
        let newItme = [this.resultKey, ...item];
        result2.find((v) => {
          if (item[0].split(".")[0] === v[0].split(".")[0]) {
            newItme.push(v[1]);
            const sortNumber = [...this.templatesList];
            const r = item[1]
              ? item[1]
                  .replace(/(([A-Za-z]+)\:[0-9]+)/g, "$2")
                  .split("、")
                  .filter((v) => v)
                  .sort((f1, f2) => {
                    return sortNumber.indexOf(f1) - sortNumber.indexOf(f2);
                  })
                  .join("、")
              : "";

            if (r === v[1].trim() || (v[1] === "阴性" && r === "IC")) {
              newItme.push("正确");
              count++;
            } else if (r.length > v[1].length) {
              newItme.push("错误");
              const arr1 = r.split("、");
              const arr2 = v[1].split("、");
              let flag = true;
              arr2.find((v) => {
                if (!arr1.includes(v)) {
                  flag = false;
                  return;
                }
              });
              if (flag) {
                count2++;
                err2.push(item);
              } else {
                err.push(item);
              }
            } else {
              newItme.push("错误");
              err.push(item);
            }
            return true;
          }
        });
        newMap.push(newItme);
      }

      console.log(newMap);
      console.log(count);
      console.log(err);
      const errDoms = err.reduce((c, r) => {
        return c + `<div>${r};</div>`;
      }, "");
      const err2Doms = err2.reduce((c, r) => {
        return c + `<div>${r};</div>`;
      }, "");
      this.$alert(
        '<div style="max-height: 70vh;overflow-y: auto">' +
          `<div>${this.resultKey}识别结果：共${
            this.fileList.length
          }张图,正确识别${count}张,假阳${count2}张,准确率${Math.floor(
            (count / this.fileList.length) * 10000
          ) / 100}%</div>` +
          "<div>错误结论为：</div>" +
          errDoms +
          "<div>假阳结论为：</div>" +
          err2Doms +
          "</div>",
        "识别结果",
        {
          confirmButtonText: "导出",
          cancelButtonText: "取消",
          showCancelButton: true,
          dangerouslyUseHTMLString: true,
          callback: (action) => {
            console.log(action);
            if (action === "confirm") {
              this.exportResultContrastData(
                newMap,
                this.form.path,
                this.resultKey + "识别结果",
                false
              );
            }
          },
        }
      );
    },
    exportResultContrastData(data, baseUrl, name, flag = false) {
      const date = parseTime(new Date(), "{y}年{m}月{d}日{h}时{i}分");

      const { writeFile } = require("fs");
      // const path = require("path");
      // const desktopPath = path.join(require("os").homedir(), "Desktop");

      // const XLSX = require("xlsx");

      // 创建一个工作簿
      const workbook = XLSX.utils.book_new();

      // 创建一个工作表
      const worksheet = XLSX.utils.json_to_sheet(data);

      worksheet.A1.v = "批次";
      worksheet.B1.v = "图片名";
      worksheet.C1.v = "软件判读";
      worksheet.D1.v = "人工判读";
      worksheet.E1.v = "结论";

      // 将工作表添加到工作簿
      XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");

      // 导出工作簿为 Excel 文件
      const excelBuffer = XLSX.write(workbook, {
        bookType: "xlsx",
        type: "buffer",
      });

      // 将 Excel 文件保存到本地
      writeFile(
        baseUrl + "\\" + name + (flag ? date : "") + ".xlsx",
        excelBuffer,
        (err) => {
          if (err) {
            this.$message.error(err);
            console.error(err);
          } else {
            this.$message({
              message: "Excel 导出成功！",
              type: "success",
            });
            console.log("Excel 导出成功！");
          }
        }
      );
    },
    async handle() {
      const cv = global.cv;

      const templates = this.findTemplate();
      this.templates = templates.RP11;

      let map = [];

      for (let i = 0; i < this.fileList.length; i++) {
        let imgDom = document.querySelector(".RP11 .img_" + i + " img");
        const mat = cv.imread(imgDom);
        const rect = this.isCropping ? this.cropping(mat, i) : mat;
        imgDom = null;
        if (rect) {
          const arr = await this.handleCompare(rect);
          rect.delete();
          let points = [];
          try {
            arr.map((v, i) => {
              const { rules, value } = v;

              let r;
              let flag = true;
              for (let u = 0; u < rules.length; u++) {
                if (rules[u].type === "trendsCount") {
                  const result = this._trendsCount(v, rules[u]);
                  if (!result) {
                    flag = false;
                    break;
                  }
                  r = result;
                }
                // else if (rules[u].type === "statistics") {
                //   const result = this._statistics(v, trendsCountResule.ratio);
                //   r = result;
                // }
              }
              if (flag) {
                points.push({
                  value: value,
                  number: Math.round(r.light - r.dark),
                });
              }

              v.gray.delete();
              v.img.delete();
              v.gray = null;
              v.img = null;
              // console.log(i, compare[i].average);
              // console.log(i, v.average - compare[i].average);
              // console.log(i, v.averageDeviation - compare[i].averageDeviation);
            });
            map.push([this.fileList[i].name, points]);
          } catch (err) {
            map.push([this.fileList[i].name, []]);
          }
        } else {
          map.push([this.fileList[i].name, []]);
        }
      }

      if (
        this.templates.compare &&
        (this.compareIndex === 0 || this.compareIndex)
      ) {
        const i = map[this.compareIndex][1].findIndex((v) => {
          return v.value === "IC";
        });
        if (i !== -1) {
          const baseMumber = map[this.compareIndex][1][i].number;

          map = map.map((v) => {
            const arr = [];
            v[1] = v[1].map((u) => {
              const item = this.determine_RP11.find((v) => {
                return Object.keys(v)[0] == u.value;
              });
              if (
                !item ||
                Math.round((u.number / baseMumber) * 100) >=
                  Object.values(item)[0]
              ) {
                arr.push(
                  u.value + ":" + Math.round((u.number / baseMumber) * 100)
                );
              }
            });
            return [v[0], arr.join("、")];
          });
          this.exportExcelData = map;
        }
      } else {
        map = map.map((v) => {
          v[1] = v[1].map((u) => {
            return u.value;
          });
          return [v[0], v[1].join("、")];
        });
        this.exportExcelData = map;
      }

      console.log(map);
      this.$message({
        message: "图片处理完成！",
        type: "success",
      });

      // this.getResult(map);

      return;
    },
    getRatios(min = 0.15, max = 0.33, particle = 0.01) {
      const l = Math.ceil((max - min) / particle);
      const remainder = (max - min) % particle;

      const ratios = [];
      for (let i = 0; i < l; i++) {
        const current = Math.round((min + i * particle) * 1000) / 1000;
        ratios.push(current);
      }
      if (remainder) {
        ratios.push(max);
      }
      return ratios;
    },
    cropping(mat, index) {
      console.log(index + "======================");
      let gray = new cv.Mat();
      cv.cvtColor(mat, gray, cv.COLOR_RGBA2GRAY);

      // const pointArr = getPoints(gray);
      // const average = mathCount(pointArr, 'average');
      // const averageDeviation = mathCount(pointArr, 'averageDeviation');

      let dst = new cv.Mat();
      cv.Canny(gray, dst, 40, 200);

      // cv.imshow("canvas", dst);

      const contours = new cv.MatVector();
      const hierarchy = new cv.Mat();
      cv.findContours(
        dst,
        contours,
        hierarchy,
        cv.RETR_EXTERNAL,
        cv.CHAIN_APPROX_SIMPLE
      );

      // 遍历轮廓并筛选出矩形轮廓
      let rectangles = [];
      let points = [];
      let mergedContour = new cv.Mat();
      for (let i = 0; i < contours.size(); i++) {
        const contour = contours.get(i);

        const color = new cv.Scalar(0, 255, 0);
        const contourIdx = i;

        const approx = new cv.Mat();
        const epsilon = 0.05 * cv.arcLength(contour, true);
        cv.approxPolyDP(contour, approx, epsilon, true);

        // 计算近似形状的周长和面积
        const perimeter = cv.arcLength(approx, true);
        // console.log(i, perimeter)

        // const { dst, ctx } = this.showImg(mat);
        // cv.drawContours(dst, contours, contourIdx, color, 1, cv.LINE_8, hierarchy, 0);
        // const imageDataWithContours = new ImageData(new Uint8ClampedArray(dst.data), dst.cols, dst.rows);
        // ctx.putImageData(imageDataWithContours, 0, 0);

        let mask = cv.Mat.zeros(mat.rows, mat.cols, cv.CV_8UC1);
        cv.drawContours(
          mask,
          contours,
          contourIdx,
          new cv.Scalar(255),
          cv.FILLED
        );
        let contourArea = cv.countNonZero(mask);

        // console.log(i, perimeter, contourArea);

        if (contourArea > 10000) {
          let contourPts = new cv.Mat();
          cv.convexHull(contour, contourPts);
          mergedContour = contourPts;
          break;
        }

        if (perimeter > 100 && contourArea > 100) {
          let contourPts = new cv.Mat();
          cv.convexHull(contour, contourPts);

          // console.log(contourPts);
          if (mergedContour.empty()) {
            mergedContour = contourPts;
          } else {
            let imageVector = new cv.MatVector();
            imageVector.push_back(mergedContour);
            imageVector.push_back(contourPts);
            cv.vconcat(imageVector, mergedContour);
            imageVector.delete();
          }
          // contourPts.delete();
          // let rect = cv.minAreaRect(contour);
          // let corners = cv.RotatedRect.points(rect);
        }
        mask.delete();
      }

      if (!mergedContour.data.length) {
        gray.delete();
        dst.delete();
        contours.delete();
        hierarchy.delete();
        mat.delete();
        mergedContour.delete();
        return;
      }

      let Rect = cv.minAreaRect(mergedContour);
      // console.log(rect);

      let center = Rect.center;
      let angle = Rect.angle;
      let width = Rect.size.width;
      let height = Rect.size.height;

      let theta = (angle * Math.PI) / 180.0;
      let cos = Math.cos(theta);
      let sin = Math.sin(theta);

      // Top-left corner
      let x1 = center.x - width / 2;
      let y1 = center.y - height / 2;
      let x1_rot = center.x + (x1 - center.x) * cos - (y1 - center.y) * sin;
      let y1_rot = center.y + (x1 - center.x) * sin + (y1 - center.y) * cos;
      points.push({ x: x1_rot, y: y1_rot });

      // Top-right corner
      let x2 = center.x + width / 2;
      let y2 = center.y - height / 2;
      let x2_rot = center.x + (x2 - center.x) * cos - (y2 - center.y) * sin;
      let y2_rot = center.y + (x2 - center.x) * sin + (y2 - center.y) * cos;
      points.push({ x: x2_rot, y: y2_rot });

      // Bottom-right corner
      let x3 = center.x + width / 2;
      let y3 = center.y + height / 2;
      let x3_rot = center.x + (x3 - center.x) * cos - (y3 - center.y) * sin;
      let y3_rot = center.y + (x3 - center.x) * sin + (y3 - center.y) * cos;
      points.push({ x: x3_rot, y: y3_rot });

      // Bottom-left corner
      let x4 = center.x - width / 2;
      let y4 = center.y + height / 2;
      let x4_rot = center.x + (x4 - center.x) * cos - (y4 - center.y) * sin;
      let y4_rot = center.y + (x4 - center.x) * sin + (y4 - center.y) * cos;
      points.push({ x: x4_rot, y: y4_rot });

      // console.log(points);
      // console.log(this.pointFilter(points));

      const rect = new cv.Mat();
      const dstSize = new cv.Size(200, 200); // 设置目标图形的大小
      const srcPts = cv.matFromArray(
        4,
        1,
        cv.CV_32FC2,
        this.pointFilter(points)
      ); // 原始图形顶点坐标
      const dstPts = cv.matFromArray(4, 1, cv.CV_32FC2, [
        0,
        0,
        200,
        0,
        200,
        200,
        0,
        200,
      ]); // 目标图形顶点坐标
      const transform = cv.getPerspectiveTransform(srcPts, dstPts); // 计算透视变换矩阵
      cv.warpPerspective(mat, rect, transform, dstSize); // 进行透视变换

      // cv.imshow("canvas", rect);
      // this.showImg(rect);

      // this.exportImg(rect, index + 1);

      gray.delete();
      dst.delete();
      contours.delete();
      hierarchy.delete();
      mat.delete();
      mergedContour.delete();
      return rect;
    },
    pointFilter(arr) {
      let xsort = arr
        .sort((f1, f2) => {
          if (f1.x === f2.x) {
            return f1.y - f2.y;
          } else {
            return f1.x - f2.x;
          }
        })
        .slice(0);

      const x1 = xsort[0];
      const x2 = xsort[xsort.length - 1];

      let ysort = arr
        .sort((f1, f2) => {
          if (f1.y === f2.y) {
            return f2.x - f1.x;
          } else {
            return f1.y - f2.y;
          }
        })
        .slice(0);
      const y1 = ysort[0];
      const y2 = ysort[ysort.length - 1];

      if (Math.abs(y1.x - x1.x) < Math.abs(y1.y - x1.y)) {
        return [y1.x, y1.y, x2.x, x2.y, y2.x, y2.y, x1.x, x1.y];
      } else {
        return [x1.x, x1.y, y1.x, y1.y, x2.x, x2.y, y2.x, y2.y];
      }
    },
    exportConfig() {
      const templates = this.findTemplate();

      const date = parseTime(new Date(), "{y}年{m}月{d}日{h}时{i}分");

      const { writeFile } = require("fs");
      const path = require("path");
      const desktopPath = path.join(require("os").homedir(), "Desktop");

      const jsonString = JSON.stringify(templates);

      writeFile(
        desktopPath + "\\RP11模板信息" + date + ".json",
        jsonString,
        (err) => {
          if (err) {
            this.$message.error(err);
            console.error(err);
          } else {
            this.$message({
              message: "模板导出成功！",
              type: "success",
            });
            console.log("Excel 导出成功！");
          }
        }
      );
    },
    exportExcel(data, baseUrl, name, flag = false) {
      const date = parseTime(new Date(), "{y}年{m}月{d}日{h}时{i}分");

      const { writeFile } = require("fs");
      // const path = require("path");
      // const desktopPath = path.join(require("os").homedir(), "Desktop");

      // const XLSX = require("xlsx");

      // 创建一个工作簿
      const workbook = XLSX.utils.book_new();

      console.log(this.exportExcelData);
      // 创建一个工作表
      const worksheet = XLSX.utils.json_to_sheet(data);

      worksheet.A1.v = "项目";
      worksheet.B1.v = "识别结果";

      // 将工作表添加到工作簿
      XLSX.utils.book_append_sheet(workbook, worksheet, "Sheet1");

      // 导出工作簿为 Excel 文件
      const excelBuffer = XLSX.write(workbook, {
        bookType: "xlsx",
        type: "buffer",
      });

      // 将 Excel 文件保存到本地
      writeFile(
        baseUrl + "\\" + name + (flag ? date : "") + ".xlsx",
        excelBuffer,
        (err) => {
          if (err) {
            this.$message.error(err);
            console.error(err);
          } else {
            this.$message({
              message: "Excel 导出成功！",
              type: "success",
            });
            console.log("Excel 导出成功！");
          }
        }
      );
    },
    // 单图片计算
    singleCount(img, index) {
      const cv = global.cv;

      let gray = new cv.Mat();

      cv.cvtColor(img, gray, cv.COLOR_RGBA2GRAY);

      let sum = 0;
      let arr = [];
      const totalPixels = gray.rows * gray.cols;

      for (let y = 0; y < gray.rows; y++) {
        for (let x = 0; x < gray.cols; x++) {
          const pixelValue = gray.ucharAt(y, x);
          if (pixelValue >= 25.5) {
            arr.push(pixelValue);
            sum += pixelValue;
          }
        }
      }

      const obj = {};

      const particle = 3;

      for (let i = 0; i < 255 / particle; i++) {
        obj[`arr${i + 1}`] = [];
      }

      arr.map((v) => {
        const i = Math.floor(v / particle);
        obj[`arr${i}`].push(v);
      });

      const dist = [];
      for (let key in obj) {
        dist.push(obj[key].length);
      }

      // const peaks = this.findPeaks(dist, 50, 1);

      console.log(dist);
      const peaks = this.findPeaks2(dist);

      // console.log(index, dist);
      // console.log(index, peaks);

      // console.log(mathCount(arr, 'sd'));

      // if (peaks[peaks.length - 1].value < 300 || peaks[peaks.length - 1].value > 600) {
      //   return;
      // }

      // const peaksIndex = peaks[peaks.length - 1].index;

      // let hight = [];

      // hight = hight.concat(obj[`arr${peaksIndex}`], obj[`arr${peaksIndex + 1}`], obj[`arr${peaksIndex + 2}`]);

      // const hightAverage = mathCount(hight, 'average');

      // const darkIndex = peaks[0].index + Math.floor((peaks[peaks.length - 1].index - peaks[0].index) / 2);

      // const darkArr = obj[`arr${darkIndex + 1}`];

      // const darkAverage = mathCount(darkArr, 'average');

      const average = mathCount(arr, "average");
      const averageDeviation = mathCount(arr, "averageDeviation");
      const sd = mathCount(arr, "sd");
      const ratio = mathCount(arr, "ratio");

      console.log(average + averageDeviation);

      const ii = Math.floor((average + averageDeviation) / particle);

      console.log(index, ii);

      const point = this.findPoint(img, average + averageDeviation);

      return point;

      // gray.delete();
      // dst.delete();
    },
    // 根据模板分割
    segment(img) {
      return new Promise((resolve) => {
        var dst = new cv.Mat();

        let imgs = [];
        this.templates.data.map((v, i) => {
          // 定义矩形的边界框
          const rect = new cv.Rect(v.left, v.top, v.width, v.height);

          let roi = new cv.Mat();
          let f = img.roi(rect);
          f.copyTo(roi);

          imgs.push({
            img: roi,
            value: v.value,
            rules: v.rules,
          });
          f.delete();
        });
        resolve(imgs);
      });

      this.result = values;

      // cv.imshow('canvas', dst);

      // cv.cvtColor(img, dst, cv.COLOR_RGBA2GRAY);

      // cv.GaussianBlur(dst, dst, new cv.Size(5, 5), 0);

      // cv.threshold(dst, dst, this.gate, 255, cv.THRESH_BINARY);

      // const kernel = cv.getStructuringElement(cv.MORPH_RECT, new cv.Size(2, 2));
      // cv.dilate(dst, dst, kernel, new cv.Point(-1, -1), 3);
      // cv.erode(dst, dst, kernel, new cv.Point(-1, -1), 1);

      // 进行边缘检测
      // const edges = new cv.Mat();
      // cv.Canny(dst, dst, 50, 150);

      // const contours = new cv.MatVector();
      // const hierarchy = new cv.Mat();
      // cv.findContours(dst, contours, hierarchy, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE);

      // for (let i = 0; i < contours.size(); i++) {
      //   const contour = contours.get(i);

      //   // 近似多边形化
      //   const epsilon = 0.05 * cv.arcLength(contour, true);
      //   const approx = new cv.Mat();
      //   cv.approxPolyDP(contour, approx, epsilon, true);

      //   // 如果近似轮廓具有四个顶点，则提取坐标
      //   if (approx.total() === 4) {
      //     const points = [];
      //     for (let j = 0; j < approx.total(); j++) {
      //       const point = approx.data32S[j];
      //       points.push({ x: point / 4, y: point % 4 });
      //     }

      //     // 输出四个端点坐标
      //     console.log(points);
      //   }

      //   approx.delete();
      //   contour.delete();

      // const rect = cv.minAreaRect(contour);

      // const vertices = cv.RotatedRect.points(rect);
      // const rectColor = new cv.Scalar(0, 255, 0, 255);

      // // 绘制旋转矩形
      // for (let j = 0; j < 4; j++) {
      //   cv.line(dst, vertices[j], vertices[(j + 1) % 4], rectColor, 2);
      // }

      //  // 进行补全和切割
      // const rectWidth = cv.RotatedRect.boundingRect(rect).width;
      // const rectHeight = cv.RotatedRect.boundingRect(rect).height;
      // const verticesArr = new cv.matFromArray(4, 1, cv.CV_32FC2, vertices);
      // const perspectiveMatrix = cv.getPerspectiveTransform(verticesArr, new cv.matFromArray(4, 1, cv.CV_32FC2, [
      //   new cv.Point(0, 0),
      //   new cv.Point(rectWidth - 1, 0),
      //   new cv.Point(rectWidth - 1, rectHeight - 1),
      //   new cv.Point(0, rectHeight - 1)
      // ]));

      // const result = new cv.Mat();
      // cv.warpPerspective(img, result, perspectiveMatrix, new cv.Size(rectWidth, rectHeight));

      // contours.delete();
      // hierarchy.delete();
      // if (squareContourIndex !== -1) {
      //   const squareContour = contours.get(squareContourIndex);
      //   const rect = cv.boundingRect(squareContour);

      //   const center = new cv.Point(rect.x + rect.width / 2, rect.y + rect.height / 2);
      //   const angle = 90; // 旋转角度

      //   const M = cv.getRotationMatrix2D(center, angle, 1);
      //   cv.warpAffine(src, dst, M, new cv.Size(rect.width, rect.height));

      //   squareContour.delete();
      //   M.delete();
      // }
    },
    contrast(points, templates) {
      const value = points.map((v) => {
        const item = templates.find((u) => {
          if (
            v.x > u.left &&
            v.x <= u.left + u.width &&
            v.y > u.top &&
            v.y <= u.top + u.height
          ) {
            return true;
          }
          return false;
        });
        return item;
      });
      console.log(value);
      this.result = value;
    },
    findTemplate() {
      const templates = require("./RP11.json");

      templates.RP11.data.forEach((v) => {
        v.rules.forEach((u) => {
          if (u.type == "trendsCount") {
            u.max = parseFloat(this[v.type].trendsCount.max);
            u.min = parseFloat(this[v.type].trendsCount.min);
            u.particle = parseFloat(this[v.type].trendsCount.particle);
            u.minContourArea = parseFloat(
              this[v.type].trendsCount.minContourArea
            );
            u.rules = this[v.type].trendsCount.rules.map((w) => {
              w.circularity = parseFloat(w.circularity);
              w.ri = {
                x: parseFloat(w.ri.x),
                y: parseFloat(w.ri.y),
              };
              return w;
            });
          } else if (u.type === "statistics") {
            if (u.min) {
              u.min = parseFloat(this[v.type].statistics.min);
            }
            if (u.max) {
              u.max = parseFloat(this[v.type].statistics.max);
            }
          }
        });
      });

      console.log(templates);
      return templates;
    },
    // findTemplate() {
    //   const parent = document.querySelector(".templates");
    //   this.width = parent.offsetWidth;
    //   this.height = parent.offsetHeight;

    //   const items = Array.from(document.getElementsByClassName("item"));

    //   const arr = items.map((v, i) => {
    //     console.log(v.offsetLeft)
    //     return {
    //       type: "normal",
    //       value: v.innerHTML.replace(/(\n|\ )/g, ''),
    //       top: v.offsetTop,
    //       left: v.offsetLeft,
    //       height: v.offsetHeight,
    //       width: v.offsetWidth,
    //       rules: [
    //         {
    //           type: "trendsCount",
    //           max: 0.33,
    //           min: 0.15,
    //           particle: 0.01,
    //           minContourArea: 225,
    //           rules: [
    //             { circularity: 0.72, ri: { x: 3.9, y: 3.9 } },
    //             { circularity: 0.85, ri: { x: 10, y: 10 } },
    //           ],
    //         },
    //       ],
    //     };
    //     // console.log(v.innerHTML, v.offsetHeight, v.offsetWidth, v.offsetTop, v.offsetLeft);
    //   });

    //   this.templates = arr;

    //   console.log(JSON.stringify(arr));
    //   return arr;
    // },
    findMaxLight(img) {
      const cv = global.cv;

      var dst = new cv.Mat();
      cv.cvtColor(img, dst, cv.COLOR_RGBA2GRAY);

      const minMaxLoc = cv.minMaxLoc(dst);
      const maxBrightness = minMaxLoc.maxVal;

      this.ratio = maxBrightness / 255;
    },
    findAverage(img) {
      const cv = global.cv;

      const imgDom = document.querySelector(`.RP11 .${img} img`);
      const mat = cv.imread(imgDom);

      var gray = new cv.Mat();

      cv.cvtColor(mat, gray, cv.COLOR_RGBA2GRAY);

      let sum = 0;
      let arr = [];

      for (let y = 0; y < gray.rows; y++) {
        for (let x = 0; x < gray.cols; x++) {
          const pixelValue = gray.ucharAt(y, x);
          if (pixelValue > 25.5) {
            arr.push(pixelValue);
            sum += pixelValue;
          }
        }
      }

      return sum / arr.length;
    },
    changeLight(old, scale) {},
    findPoint(item, ratio, rule, diff) {
      const cv = global.cv;

      let dst = new cv.Mat();

      // cv.cvtColor(img, dst, cv.COLOR_RGBA2GRAY);
      // cv.cvtColor(img, dst, 6);
      cv.GaussianBlur(item.gray, dst, new cv.Size(3, 3), 0);
      // const kernel = cv.getStructuringElement(cv.MORPH_RECT, new cv.Size(1, 1));
      // cv.dilate(dst, dst, kernel, new cv.Point(-1, -1), 1);
      // cv.erode(dst, dst, kernel, new cv.Point(-1, -1), 1);

      // let arr = [];

      // for (let y = 0; y < dst.rows; y++) {
      //   for (let x = 0; x < dst.cols; x++) {
      //     const pixelValue = dst.ucharAt(y, x);
      //     if (pixelValue >= 25.5) {
      //       arr.push(pixelValue);
      //     }
      //   }
      // }

      // const average = mathCount(arr, 'average');
      // const averageDeviation = mathCount(arr, 'averageDeviation');
      // const sd = mathCount(arr, 'sd');

      // const ratio = average + averageDeviation;

      cv.threshold(dst, dst, ratio, 255, cv.THRESH_BINARY)[1];
      // this.showImg(dst);

      // cv.Canny(img, dst, 0, 150);

      const mode = cv.RETR_EXTERNAL; // 只检测最外层轮廓
      const method = cv.CHAIN_APPROX_SIMPLE; // 仅保存端点
      const contours = new cv.MatVector();
      const hierarchy = new cv.Mat();

      // let mergedContour = new cv.Mat();
      cv.findContours(dst, contours, hierarchy, mode, method);

      // const minContourArea = 225; // 最小轮廓面积
      let points = [];
      let circularitys = [];
      let index = "";
      for (let i = 0; i < contours.size(); i++) {
        const contour = contours.get(i);
        // cv.drawContours(
        //   dst2,
        //   contours,
        //   i,
        //   [255, 255, 255, 255],
        //   2,
        //   cv.LINE_8,
        //   hierarchy,
        //   0
        // );

        // const contourIdx = i;
        // const color = new cv.Scalar(0, 255, 0);
        // const { dst, ctx } = this.showImg(item.img);
        // cv.drawContours(
        //   dst,
        //   contours,
        //   contourIdx,
        //   color,
        //   1,
        //   cv.LINE_8,
        //   hierarchy,
        //   0
        // );
        // const imageDataWithContours = new ImageData(
        //   new Uint8ClampedArray(dst.data),
        //   dst.cols,
        //   dst.rows
        // );
        // ctx.putImageData(imageDataWithContours, 0, 0);

        const moment = cv.moments(contour, false);
        const x = moment.m10 / moment.m00; // X 坐标
        const y = moment.m01 / moment.m00; // Y 坐标

        const contourArea = cv.contourArea(contour);

        const epsilon = 0.02 * cv.arcLength(contour, true);
        const approx = new cv.Mat();
        cv.approxPolyDP(contour, approx, epsilon, true);

        // 计算近似形状的周长和面积
        const perimeter = cv.arcLength(approx, true);
        const area = cv.contourArea(approx);

        // 判断是否接近圆形
        const circularity = (4 * Math.PI * area) / (perimeter * perimeter);

        // console.log("circularity", area, circularity);

        // console.log('area', area);
        // console.log('circularity', circularity);
        // console.log('point', {
        //     area: area,
        //     x,
        //     y,
        // });
        if (area > (rule.minContourArea || 168)) {
          circularitys.push(circularity);
          points.push({
            area: area,
            x,
            y,
          });
          index = i;
        }

        // const circularityThreshold = 0.45; // 圆形度的阈值，越接近于1表示越接近圆形
        // let flag = false;
        // rule.rules.map((v) => {
        //   if (area > v.minContourArea) {
        //     if (
        //       circularity > v.circularity &&
        //       y < dst.rows / 2 + v.ri.y &&
        //       y > dst.rows / 2 - v.ri.y &&
        //       x < dst.cols / 2 + v.ri.x &&
        //       x > dst.cols / 2 - v.ri.x
        //     ) {
        //       console.log({ x, y });
        //       flag = true;
        //     }
        //   }
        // });
        // if (flag) {
        //   points.push({ x, y });
        // }
        contour.delete();
        approx.delete();
      }

      if (diff) {
        let insidePoints = [];
        let outsidePoints = [];
        for (let y = 0; y < item.img.rows; y++) {
          for (let x = 0; x < item.img.cols; x++) {
            const contour = contours.get(index);
            if (cv.pointPolygonTest(contour, new cv.Point(x, y), false) >= 0) {
              insidePoints.push(item.img.ucharPtr(y, x)[0]);
            } else {
              outsidePoints.push(item.img.ucharPtr(y, x)[0]);
            }
            contour.delete();
          }
        }

        const insideAvg =
          insidePoints.reduce((a, b) => a + b, 0) / insidePoints.length;
        const outsideAvg =
          outsidePoints.reduce((a, b) => a + b, 0) / outsidePoints.length;

        console.log("轮廓内亮点大于外围的亮度值：" + (insideAvg - outsideAvg));

        contours.delete();
        hierarchy.delete();
        dst.delete();

        // if (circularitys > 0.92) {
        return {
          light: insideAvg,
          dark: outsideAvg,
        };
        // } else if (circularitys > 0.85 && insideAvg - outsideAvg > 30) {
        //   return {
        //     light: insideAvg,
        //     dark: outsideAvg,
        //   };
        // } else if (insideAvg - outsideAvg > 50) {
        //   return {
        //     light: insideAvg,
        //     dark: outsideAvg,
        //   };
        // } else {
        //   return false;
        // }
      }

      contours.delete();
      hierarchy.delete();
      dst.delete();
      // this.showImg(dst2);

      // const points2 = points.map(v => {
      //   return {
      //     x: v.x / img.rows * this.width,
      //     y: v.y / img.cols * this.height,
      //   }
      // })
      return { circularitys, points };
    },
    findPoint2(img) {
      const cv = global.cv;

      var blurred = new cv.Mat();
      cv.cvtColor(img, blurred, cv.COLOR_RGBA2GRAY);

      cv.GaussianBlur(blurred, blurred, new cv.Size(3, 3), 0);

      const threshold = 150; // 亮度差异的阈值
      const brighterPoints = [];

      for (let y = 1; y < blurred.rows - 1; y++) {
        for (let x = 1; x < blurred.cols - 1; x++) {
          const centerValue = blurred.ucharAt(y, x)[0];
          let isBrighter = true;

          // 检查周围8个像素是否都比中心像素暗
          for (let dy = -1; dy <= 1; dy++) {
            for (let dx = -1; dx <= 1; dx++) {
              if (dy === 0 && dx === 0) continue;

              const neighborValue = blurred.ucharAt(y + dy, x + dx)[0];

              if (neighborValue >= centerValue + threshold) {
                isBrighter = false;
                break;
              }
            }
            if (!isBrighter) break;
          }

          if (isBrighter) {
            brighterPoints.push({ x: x, y: y });
          }
        }
      }

      const point = brighterPoints.map((v) => {
        return {
          x: (v.x / img.rows) * this.width,
          y: (v.y / img.cols) * this.height,
        };
      });

      return point;
    },
    // showImg(result) {
    //   // 在页面上显示结果
    //   const resultCanvas = document.createElement("canvas");
    //   resultCanvas.width = result.cols;
    //   resultCanvas.height = result.rows;

    //   const resultCtx = resultCanvas.getContext("2d");
    //   let resultImageData = new ImageData(
    //     new Uint8ClampedArray(
    //       result.data.length === result.cols * result.rows * 4
    //         ? result.data
    //         : this.processGrayscaleImage(result)
    //     ),
    //     result.cols,
    //     result.rows
    //   );

    //   resultCtx.putImageData(resultImageData, 0, 0);

    //   document.querySelector(".templates").appendChild(resultCanvas);
    // },
    showImg(img) {
      let dst = new cv.Mat();
      img.copyTo(dst);

      const canvas = document.createElement("canvas");
      document.body.appendChild(canvas);

      const ctx = canvas.getContext("2d");

      const imageData = new ImageData(
        new Uint8ClampedArray(
          dst.data.length === dst.cols * dst.rows * 4
            ? dst.data
            : this.processGrayscaleImage(dst)
        ),
        dst.cols,
        dst.rows
      );

      canvas.width = imageData.width;
      canvas.height = imageData.height;

      ctx.putImageData(imageData, 0, 0);

      return { dst, ctx };
    },
    processGrayscaleImage(imageData) {
      const width = imageData.cols;
      const height = imageData.rows;

      // 获取灰度图像的像素数据
      const data = imageData.data;

      let arr = [];

      // 处理每个像素
      for (let i = 0; i < data.length; i++) {
        // 获取当前像素的灰度值（灰度图像只有一个通道）
        const grayValue = data[i];

        arr = arr.concat([grayValue, grayValue, grayValue, 255]);
      }

      arr = new Uint8Array(arr);

      return arr;
    },
    findPeaks2(arr) {
      const obj = {};

      const particle = 3;

      for (let i = 0; i < 255 / particle; i++) {
        obj[`arr${i + 1}`] = [];
      }

      arr.map((v) => {
        const i = Math.floor(v / particle);
        obj[`arr${i}`].push(v);
      });

      const dist = [];
      for (let key in obj) {
        dist.push(obj[key].length);
      }

      const peaks = [];

      for (let i = 0; i < dist.length - 7; i++) {
        peaks.push(
          dist[i] +
            dist[i + 1] +
            dist[i + 2] +
            dist[i + 3] +
            dist[i + 4] +
            dist[i + 5] +
            dist[i + 6]
        );
      }
      console.log(peaks);

      return this.findPeaks(peaks, 100, 1);
    },
    findPeaks(arr, base = 0, threshold = 1) {
      const peaks = [];

      for (let i = 0; i < arr.length; i++) {
        const currentValue = arr[i];
        let isPeak = true;

        for (let j = i - threshold; j <= i + threshold; j++) {
          if (arr[j] && arr[j] > currentValue) {
            isPeak = false;
            break;
          }
        }

        if (isPeak && currentValue > base) {
          peaks.push({ index: i, value: currentValue });
        }
      }
      console.log(peaks);
      const peaks2 = [];
      for (let i = 0; i < peaks.length; i++) {
        if (
          i !== peaks.length - 1 &&
          Math.abs(peaks[i].index - peaks[i + 1].index) <= 2
        ) {
        } else {
          peaks2.push(peaks[i]);
        }
      }
      console.log(peaks2);
      return peaks2;
    },
    showOutline(img) {
      const cv = global.cv;

      let dst = new cv.Mat();

      cv.cvtColor(img, dst, cv.COLOR_RGBA2GRAY);

      const contours = new cv.MatVector();
      const hierarchy = new cv.Mat();
      cv.findContours(
        dst,
        contours,
        hierarchy,
        cv.RETR_EXTERNAL,
        cv.CHAIN_APPROX_SIMPLE
      );

      console.log(contours.size());

      // 假设 contours 是一个 OpenCV.js 中的轮廓数据
      const contourImage = new cv.Mat(img.rows, img.cols, 1);
      const color = new cv.Scalar(255, 0, 0); // 轮廓图的颜色为白色

      cv.drawContours(contourImage, contours, -1, color, cv.FILLED, cv.LINE_8);
    },
  },
};
</script>

<style rel="stylesheet/scss" lang="scss" scoped>
@import "../../styles/mixin.scss";

.RP11 {
  position: relative;
  display: flex;
  flex-direction: row;
  background: #ffffff;
  // padding: 16px;
  height: calc(100vh - #{$header-height});

  .main {
    width: calc(100% - 308px - 16px);
    height: calc(100vh - #{$header-height});

    /deep/ .el-scrollbar__wrap {
      overflow-x: hidden;
    }
  }

  .panel {
    // padding: 16px 0;
    padding-left: 16px;
    width: 308px;
    position: fixed;
    top: calc(16px + #{$header-height});
    right: 16px;
    height: calc(100vh - #{$header-height} - 32px);
    border-left: 1px solid #e5e6eb;
    display: flex;
    flex-direction: column;

    .el-divider {
      margin: 12px 0;
    }

    .List {
      flex: 1 1 auto;
      height: 100%;
      width: 100%;

      .Table {
        width: 100%;
        display: flex;
        flex-direction: column;
        font-size: 14px;
        color: #1d2129;

        .t-row {
          display: flex;
          flex-direction: row;
          align-items: center;
          background: #ffffff;
          cursor: pointer;

          .t-column-1,
          .t-column-2 {
            padding-left: 16px;
            height: 48px;
            line-height: 48px;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
          }

          .t-column-1 {
            width: 80px;
          }

          .t-column-2 {
            width: 212px;
          }
        }

        .t-head {
          font-size: 14px;
          font-weight: 500;
          color: #4e5969;
          line-height: 20px;
          background: #f7f8fa;
          cursor: default;
        }
      }
    }
  }

  .panel {
    /deep/ .el-scrollbar__wrap {
      overflow-x: hidden;
    }

    .btns {
      margin-top: 5px;
      width: 200px;
      display: flex;
      flex: row;
      flex-wrap: wrap;

      .btn {
        margin-left: 0px;

        &:nth-child(2n) {
          margin-left: 5px;
        }

        &:nth-child(n + 3) {
          margin-top: 5px;
        }
      }
    }

    .block {
      display: flex;
      flex-direction: column;
    }

    .row {
      display: flex;
      flex-direction: row;
      align-items: center;
      font-size: 14px;
      margin-top: 12px;
      color: #1d2129;
      line-height: 16px;

      .input {
        width: 50px;
        margin: 0 5px;

        /deep/ .el-input__inner {
          padding: 0 5px;
        }
      }
    }
  }

  .imgs {
    padding: 16px;
    display: grid;
    grid-template-columns: repeat(auto-fill, 150px);
    grid-gap: 15px;

    > div {
      display: flex;
      flex-direction: column;

      p {
        margin-top: 8px;
        font-size: 14px;
        color: #1d2129;
        line-height: 22px;
      }
    }
  }

  .img {
    width: 150.02px;
    height: 150.02px;
    border-radius: 2px;
  }

  .active {
    box-shadow: 0 0 0 4px #165dff;
  }

  .templates {
    // height: 200px;
    width: 150px;
    height: 150px;
    display: flex;
    flex-direction: row;
    align-content: flex-start;
    flex-wrap: wrap;
    position: relative;

    .item {
      height: 37.5px;
      width: 37.5px;
      display: flex;
      align-items: center;
      justify-content: center;
      font-size: 12px;
    }
  }
}

.form {
  .item {
    display: flex;
    flex-direction: row;
    align-items: center;

    /deep/ input {
      height: 32px;
      font-size: 14px;
      color: #86909c;
      line-height: 22px;
      padding-left: 12px;
    }

    .btn {
      width: 60px;
      height: 32px;
      border-radius: 2px 2px 2px 2px;
      margin-left: 12px;
      padding: 0 16px;
    }
  }
}

.Dialog-box {
  width: 300px;
  height: 300px;
  display: flex;
  flex-direction: row;
  flex-wrap: wrap;

  .box {
    height: 100px;
    width: 75px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;

    .input {
      margin-top: 10px;
    }

    /deep/ input {
      text-align: center;
    }
  }
}
</style>
